package com.botann.projects.utils;

import com.botann.projects.base.UserDetail;
import com.botann.projects.base.UserDetailType;
import com.botann.projects.service.AdminUserServiceIntf;
import com.botann.projects.model.UserSecret;
import com.botann.projects.service.AdminUserServiceIntf;
import com.alibaba.druid.util.HexBin;
import com.botann.projects.base.UserDetail;
import com.botann.projects.base.UserDetailType;
import org.apache.log4j.Logger;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * StorageManager
 * TokenUtils
 * Created by 刘山国 on 2017/5/29.
 * Copyright (c) 2017 刘山国. All rights reserved.
 */
public final class TokenUtils
{
    private static Logger logger = Logger.getLogger(TokenUtils.class);

    public static final String MAGIC_KEY = "obfuscate";
    public static final String TOKEN_COOKIE_NAME = "pxx";
    public static final Integer iIndex = 2;
    public static final Integer pIndex = 0;
    public static final Integer sIndex = 3;
    public static final Integer tIndex = 1;
    public static final Integer uIndex = 4;

    public static String createToken(UserDetail userDetail, String platform, HttpServletResponse response) {
        String token = createToken(userDetail,platform);
        responseCookie(response, token);
        return token;
    }

    public static void responseCookie(HttpServletResponse response, String token) {
        Cookie cookie = new Cookie(TOKEN_COOKIE_NAME,token);
        cookie.setPath("/");
        cookie.setHttpOnly(true);
        response.addCookie(cookie);
        response.addHeader("token",cookie.getValue());

//        cookie.setPath("/charging");
//        cookie.setMaxAge(60*60*24);
//        cookie.setDomain(".botann.com");
    }


    public static void updateToken(UserDetail userDetail,String token,HttpServletResponse response){
        token = createToken(userDetail,getPlatFormFromToken(token));
        responseCookie(response, token);
    }

    public static void clearToken(HttpServletResponse response) {
        Cookie cookie = new Cookie(TOKEN_COOKIE_NAME,"xx");
        cookie.setPath("/");
        response.addCookie(cookie);
    }


    private static String createToken(UserDetail userDetails, String platform)
    {
      /* Expires in half an hour */
//        long expires = System.currentTimeMillis() + 1000L * 60 / 6;
        long expires = System.currentTimeMillis() + 1000L * 60 * 60 * 2;
        StringBuilder tokenBuilder = new StringBuilder();
        tokenBuilder.append(platform);
        tokenBuilder.append(":");
        tokenBuilder.append(expires);
        tokenBuilder.append(":");
        tokenBuilder.append(userDetails.getId());
        tokenBuilder.append(":");
        tokenBuilder.append(TokenUtils.computeSignature(userDetails.getId()));
        tokenBuilder.append(":");
        tokenBuilder.append(userDetails.getType().rawValue());

        return tokenBuilder.toString();
    }


    private static String computeSignature(Integer userId)
    {
        StringBuilder signatureBuilder = new StringBuilder();
        signatureBuilder.append(userId);
        signatureBuilder.append(":");
        signatureBuilder.append(TokenUtils.MAGIC_KEY);

        MessageDigest digest;
        try {
            digest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException("No MD5 algorithm available!");
        }

        String hexString = HexBin.encode(digest.digest(signatureBuilder.toString().getBytes()));
        return new String(hexString);
    }


    public static String getPlatFormFromToken(String authToken) {
        if (!authToken.contains(":")) {
            logger.error("错误,getPlatFormFromToken: "+authToken);
            return null;
        }
        String[] parts = authToken.split(":");
        if (parts.length<=pIndex) {
            logger.error("错误,getPlatFormFromToken: "+authToken);
            return null;
        }
        return parts[pIndex];
    }



    public static Object checkSign (String token, AdminUserServiceIntf service, HttpServletRequest request, HttpServletResponse response) {
        if (null == token) return "没有token";
        String[] parts = token.split(":");
        if (parts.length<5) return "token格式非法";
        try {

            long expires = Long.parseLong(parts[tIndex]);
            boolean isExpire = expires < System.currentTimeMillis();
            if (isExpire) {
                return "登录超时~";
            } else {
                Integer userId = Integer.parseInt(parts[iIndex]);
                String signature = parts[sIndex];
                // 0.cookie值防篡改签名验证
                boolean isSame = signature.equals(computeSignature(userId));

                if (isSame) {
                    UserDetailType type = UserDetailType.rawWith(Integer.parseInt(parts[uIndex]));
                    // 1.参数签名验证
                    UserSecret userSecret = service.loadUserSecret(userId,type.rawValue());
                    if (userSecret == null) return "用户不存在!";
                    if (userSecret.getExpireTime().getTime() < System.currentTimeMillis()) return "登录超时!";
                    String toSign = signParams(request.getParameterMap());
                    toSign = toSign + "&secretKey=" + MD5Utils.md5(userSecret.getPassword()+userSecret.getSecretKey());
                    if (MD5Utils.md5(toSign).equals(request.getParameter("sign"))) {
                        UserDetail userDetail = new UserDetail(type,userId);
                        updateToken(userDetail,token,response);
                        return userId;
                    } else {
                        return "参数验证失败!";
                    }
                } else {
                    return "签名不一致!";
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            String error = e.toString();
            return error.length()>240?error.substring(0,240):error;
        }
    }

    private static String signParams(Map<String, String[]> params) {
        List<String> keys = new ArrayList<>(params.keySet());
        Collections.sort(keys);
        String prestr = "";
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            if (key.equals("sign")) continue;
            String [] values = params.get(key);
            String value = values[0];
            if (i == keys.size() - 1) {// 拼接时，不包括最后一个&字符
                prestr = prestr + key + "=" + value;
            } else {
                prestr = prestr + key + "=" + value + "&";
            }
        }
        return prestr;
    }


}
